Skip to content

Conversation

@dmpots
Copy link
Contributor

@dmpots dmpots commented Nov 18, 2025

This commit adds a MockDwarfDelegate class that can be used to control what dwarf version is used when evaluating an expression. We also add a simple test that shows how dwarf version can change the result of the expression.

@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2025

@llvm/pr-subscribers-lldb

Author: David Peixotto (dmpots)

Changes

This commit adds a MockDwarfDelegate class that can be used to control what dwarf version is used when evaluating an expression. We also add a simple test that shows how dwarf version can change the result of the expression.


Full diff: https://github.com/llvm/llvm-project/pull/168468.diff

1 Files Affected:

  • (modified) lldb/unittests/Expression/DWARFExpressionTest.cpp (+59-1)
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 13110ef7cbb0a..88bbf863e4435 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -39,6 +39,51 @@ using namespace lldb_private;
 using namespace llvm::dwarf;
 
 namespace {
+/// A mock implementation of DWARFExpression::Delegate for testing.
+/// This class provides default implementations of all delegate methods,
+/// with the DWARF version being configurable via the constructor.
+class MockDwarfDelegate : public DWARFExpression::Delegate {
+public:
+  static constexpr uint16_t DEFAULT_DWARF_VERSION = 5;
+  static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); }
+  static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); }
+
+  MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}
+  explicit MockDwarfDelegate(uint16_t version) : m_version(version) {}
+
+  uint16_t GetVersion() const override { return m_version; }
+
+  dw_addr_t GetBaseAddress() const override { return 0; }
+
+  uint8_t GetAddressByteSize() const override { return 4; }
+
+  llvm::Expected<std::pair<uint64_t, bool>>
+  GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "GetDIEBitSizeAndSign not implemented");
+  }
+
+  dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const override {
+    return 0;
+  }
+
+  lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
+                                          const lldb::offset_t data_offset,
+                                          const uint8_t op) const override {
+    return LLDB_INVALID_OFFSET;
+  }
+
+  bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+                              lldb::offset_t &offset, RegisterContext *reg_ctx,
+                              lldb::RegisterKind reg_kind,
+                              DWARFExpression::Stack &stack) const override {
+    return false;
+  }
+
+private:
+  uint16_t m_version;
+};
+
 struct MockProcess : Process {
   MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
       : Process(target_sp, listener_sp) {}
@@ -164,7 +209,7 @@ class MockRegisterContext : public RegisterContext {
 
 static llvm::Expected<Value> Evaluate(llvm::ArrayRef<uint8_t> expr,
                                       lldb::ModuleSP module_sp = {},
-                                      DWARFUnit *unit = nullptr,
+                                      DWARFExpression::Delegate *unit = nullptr,
                                       ExecutionContext *exe_ctx = nullptr,
                                       RegisterContext *reg_ctx = nullptr) {
   DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
@@ -505,6 +550,19 @@ TEST(DWARFExpression, DW_OP_stack_value) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
 }
 
+TEST(DWARFExpression, dwarf_version) {
+  MockDwarfDelegate dwarf2 = MockDwarfDelegate::Dwarf2();
+  MockDwarfDelegate dwarf5 = MockDwarfDelegate::Dwarf5();
+
+  // In dwarf2 the constant on top of the stack is treated as a value.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf2), ExpectScalar(1));
+
+  // In dwarf5 the constant on top of the stack is implicitly converted to an
+  // address.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf5),
+                       ExpectLoadAddress(1));
+}
+
 TEST(DWARFExpression, DW_OP_piece) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,
                                  DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),

@github-actions
Copy link

github-actions bot commented Nov 18, 2025

🐧 Linux x64 Test Results

  • 33167 tests passed
  • 495 tests skipped

This commit adds a `MockDwarfDelegate` class that can be used to control
what dwarf version is used when evaluating an expression. We also add a
simple test that shows how dwarf version can change the result of the
expression.
Copy link
Collaborator

@clayborg clayborg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch to std::optional and this will be good

@dmpots dmpots merged commit 89206de into llvm:main Nov 24, 2025
10 checks passed
aadeshps-mcw pushed a commit to aadeshps-mcw/llvm-project that referenced this pull request Nov 26, 2025
…8468)

This commit adds a `MockDwarfDelegate` class that can be used to control
what dwarf version is used when evaluating an expression. We also add a
simple test that shows how dwarf version can change the result of the
expression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants